#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>

// 打印进程ID和信号状态
void print_status(pid_t pid, const std::string &action, int signo)
{
    std::cout << "Process " << pid << " " << action << " signal " << signo << std::endl;
}

// 信号处理函数（仅用于演示信号被递送）
void handlerSig(int signo)
{
    print_status(getpid(), "收到并处理", signo);
}

int main()
{
    // 子进程1：演示“忽略信号”（SIGINT）
    pid_t pid1 = fork();
    if (pid1 == 0)
    {
        // 忽略SIGINT信号（2号信号，通常由Ctrl+C触发）
        signal(SIGINT, SIG_IGN);
        print_status(getpid(), "已设置忽略", SIGINT);

        // 等待信号触发（10秒）
        for (int i = 0; i < 10; ++i)
        {
            sleep(1); // 休眠1秒（系统调用：挂起进程指定时间）

            // 检查当前进程的“挂起信号集”（未被递送的信号）
            sigset_t pending;     // 定义信号集变量
            sigpending(&pending); // 系统调用：获取当前进程的挂起信号集

            // 判断SIGINT是否在挂起信号集中
            if (sigismember(&pending, SIGINT))
            {
                print_status(getpid(), "发现挂起的", SIGINT); // 这行会执行
            }
        }

        print_status(getpid(), "正常退出", 0);
        return 0;
    }

    // 子进程2：演示“屏蔽信号”（SIGINT）
    pid_t pid2 = fork();
    if (pid2 == 0)
    {
        // 注册SIGINT的处理函数（收到信号后执行handlerSig）
        signal(SIGINT, handlerSig);

        // 屏蔽SIGINT信号（信号被阻塞，暂时不递送）
        sigset_t block;            // 定义信号集变量
        sigemptyset(&block);       // 初始化信号集为空（系统调用：清空信号集）
        sigaddset(&block, SIGINT); // 系统调用：向信号集添加SIGINT
        // 系统调用：设置进程的“信号屏蔽字”（阻塞block中的信号）
        sigprocmask(SIG_BLOCK, &block, nullptr);
        print_status(getpid(), "已设置屏蔽", SIGINT);

        // 等待信号触发（10秒），并检查挂起状态
        for (int i = 0; i < 10; ++i)
        {
            sleep(1);
            sigset_t pending;
            sigpending(&pending);
            if (sigismember(&pending, SIGINT))
            {
                print_status(getpid(), "发现挂起的", SIGINT); // 这行会执行
            }
        }

        // 5秒后解除屏蔽
        print_status(getpid(), "开始解除屏蔽", SIGINT);
        sigprocmask(SIG_UNBLOCK, &block, nullptr); // 系统调用：解除屏蔽

        // 解除屏蔽后等待1秒（观察信号处理）
        sleep(1);
        print_status(getpid(), "正常退出", 0);
        return 0;
    }

    // 父进程：向两个子进程发送SIGINT（3秒后）
    sleep(3);
    std::cout << "\n父进程向两个子进程发送SIGINT..." << std::endl;

    // 向子进程1和2发送SIGINT信号（2号信号）
    kill(pid1, SIGINT);
    kill(pid2, SIGINT);  

    // 等待子进程结束（回收资源）
    waitpid(pid1, nullptr, 0);
    waitpid(pid2, nullptr, 0);

    std::cout << "\n所有子进程结束" << std::endl;
    return 0;
}